package com.dm.base.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.dm.base.domain.BDb;
import com.dm.base.domain.BTask;
import com.dm.base.mapper.BTaskMapper;
import com.dm.base.service.IBTaskService;
import com.dm.common.core.redis.RedisCache;
import com.dm.common.enums.TaskStatus;
import com.dm.common.enums.TaskType;
import com.dm.common.utils.DateUtils;
import com.dm.common.utils.StringUtils;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 任务Service业务层处理
 *
 * @author dm
 * @date 2024-12-06
 */
@Service
public class BTaskServiceImpl implements IBTaskService {
    @Resource
    private BTaskMapper bTaskMapper;
    @Resource
    private BDbServiceImpl dbService;
    @Autowired
    private RedisCache redisCache;
    private String[] sqlCantCon = {"insert", "update", "drop", "alter", "delete"};

    /**
     * 查询任务
     *
     * @param taskId 任务主键
     * @return 任务
     */
    @Override
    public BTask selectBTaskByTaskId(Long taskId) {
        BTask task = bTaskMapper.selectBTaskByTaskId(taskId);
        Object cacheObject = redisCache.getCacheObject(String.valueOf(task.getTaskId()));
        task.setDoTimes(cacheObject != null ? Long.parseLong(cacheObject.toString()) : 0L);
        return task;
    }

    /**
     * 查询任务列表
     *
     * @param bTask 任务
     * @return 任务
     */
    @Override
    public List<BTask> selectBTaskList(BTask bTask) {
        List<BTask> list = bTaskMapper.selectBTaskList(bTask);
        List<BTask> collect = list.stream().map(d -> {
            Object cacheObject = redisCache.getCacheObject(String.valueOf(d.getTaskId()));
            d.setDoTimes(cacheObject != null ? Long.parseLong(cacheObject.toString()) : 0L);
            return d;
        }).collect(Collectors.toList());
        return collect;
    }

    /**
     * 新增任务
     *
     * @param bTask 任务
     * @return 结果
     */
    @Override
    public int insertBTask(BTask bTask) {
        bTask.setCreateTime(DateUtils.getNowDate());
        return bTaskMapper.insertBTask(bTask);
    }

    /**
     * 修改任务
     *
     * @param bTask 任务
     * @return 结果
     */
    @Override
    public int updateBTask(BTask bTask) {
        bTask.setUpdateTime(DateUtils.getNowDate());
        return bTaskMapper.updateBTask(bTask);
    }

    /**
     * 批量删除任务
     *
     * @param taskIds 需要删除的任务主键
     * @return 结果
     */
    @Override
    public int deleteBTaskByTaskIds(Long[] taskIds) {
        return bTaskMapper.deleteBTaskByTaskIds(taskIds);
    }

    /**
     * 删除任务信息
     *
     * @param taskId 任务主键
     * @return 结果
     */
    @Override
    public int deleteBTaskByTaskId(Long taskId) {
        return bTaskMapper.deleteBTaskByTaskId(taskId);
    }

    @Override
    public int doTask(Long taskId) {
        redisCache.deleteObject(String.valueOf(taskId));
        BTask bTask = selectBTaskByTaskId(taskId);
        bTask.setStatus(TaskStatus.GOING.getCode());
        BDb bDb = dbService.selectBDbByDbId(bTask.getDbId());
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection conn = DriverManager.getConnection(
                    "jdbc:mysql://" + bDb.getUrl() + ":" + bDb.getPort() + "/" + bDb.getDbName() + "?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8",
                    bDb.getLoginName(),
                    bDb.getLoginPassword());
            Statement st = conn.createStatement();
            new Thread("sqlTaskRun") {
                @Override
                public void run() {
                    try {
                        doTaskSql(conn, st, bTask);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            return 1;
        } catch (Exception e) {
            bTask.setStatus(TaskStatus.ERROR.getCode());
        } finally {
            updateBTask(bTask);
        }
        return 0;
    }

    @Override
    public String doExecute(BTask bTask) {
        for (String s : sqlCantCon) {
            if (bTask.getName().toLowerCase().indexOf(s) >= 0) {
                return "不能包含" + s;
            }
        }
        BDb bDb = dbService.selectBDbByDbId(bTask.getDbId());
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection conn = DriverManager.getConnection(
                    "jdbc:mysql://" + bDb.getUrl() + ":" + bDb.getPort() + "/" + bDb.getDbName() + "?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8",
                    bDb.getLoginName(),
                    bDb.getLoginPassword());
            Statement st = conn.createStatement();
            return doExecuteSql(conn, st, bTask);
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    public void doTaskSql(Connection conn, Statement st, BTask bTask) throws Exception {
        String sqlDel = "delete from " + bTask.getFromTable() + " " + bTask.getRemark() + " limit " + bTask.getNum() + ";";
        String sqlCopy = "insert into " + bTask.getToTable() + " select * from " + bTask.getFromTable() + " " + bTask.getRemark() + " limit " + bTask.getNum() + ";";
        try {
            conn.setAutoCommit(false);
            Long times = bTask.getTimes();
            Long doTimes = 0L;
            redisCache.setCacheObject(String.valueOf(bTask.getTaskId()), doTimes);
            while (doTimes < times) {
                if (doTimes > 0) {
                    Thread.sleep(1000);
                }
                if (TaskType.ONLYDEL.getCode().equals(bTask.getType())) {
                    st.executeUpdate(sqlDel);
                }
                if (TaskType.ONLYCOPY.getCode().equals(bTask.getType())) {
                    String sql = "insert into " + bTask.getToTable() + " select * from " + bTask.getFromTable() + " " + bTask.getRemark() + " limit " + doTimes * bTask.getNum() + "," + bTask.getNum() + ";";
                    st.executeUpdate(sql);
                }
                if (TaskType.COPYANDDEL.getCode().equals(bTask.getType())) {
                    st.executeUpdate(sqlCopy);
                    st.executeUpdate(sqlDel);
                }
                conn.commit();
                doTimes++;
                redisCache.setCacheObject(String.valueOf(bTask.getTaskId()), doTimes);
            }
            bTask.setStatus(TaskStatus.OVER.getCode());
            updateBTask(bTask);
            st.close();
            conn.close();
        } catch (Exception e) {
            redisCache.setCacheObject(String.valueOf(bTask.getTaskId()), 0);
            conn.rollback();
            bTask.setStatus(TaskStatus.ERROR.getCode());
        } finally {
            updateBTask(bTask);
        }
    }


    public String doExecuteSql(Connection conn, Statement st, BTask bTask) throws Exception {
        List list = new ArrayList();
        conn.setAutoCommit(false);
        ResultSet resultSet = st.executeQuery(bTask.getName());
        ResultSetMetaData metaData = resultSet.getMetaData();
        while (resultSet.next()) {
            JSONObject map = new JSONObject();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                map.put(metaData.getColumnLabel(i), resultSet.getObject(i));
            }
            list.add(map);
        }
        resultSet.close();
        st.close();
        conn.close();
        return list.toString();
    }
}
